// ========== Copyright Header Begin ==========================================
// 
// OpenSPARC T1 Processor File: simkern.cc
// Copyright (c) 2006 Sun Microsystems, Inc.  All Rights Reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
// 
// The above named program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License version 2 as published by the Free Software Foundation.
// 
// The above named program is distributed in the hope that it will be 
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
// 
// You should have received a copy of the GNU General Public
// License along with this work; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
// 
// ========== Copyright Header End ============================================
#pragma ident "@(#)1.11	02/09/24	simkern.cc"
#include "bcore/InstructionEmulator.h"
#include "bcore/cpu_exec2.h"
#include "bcore/cpu_exec3.h"
#include "bcore/v9_inst_asm.h"
#include <cassert>
#include "Sf/Sf_Trap.h"
#include "CallbackInterface.h"

#define LO_W(ll) ( ll & 0x0ffffffffULL )
using namespace std;
using namespace Riesling;

//
// Decode/Execute SPARC v9 iset engine
// 

//////////////////////////////////////////
/*
* Basic enumeration for the instruction types (op field) opcodes.
*/

typedef enum {
    Ty_0	= 0,	/* branches and SETHI */
    Ty_1	= 1,	/* CALL               */
    Ty_2	= 2,	/* arithmetic & Misc  */
    Ty_3	= 3	/* Loads/Stores       */
} ty_code_t;

/*
* An enumeration table for the op2 values for op==0
*/

typedef enum {
    T0o3_Illtrap = 0,	T0o3_BPcc,
    T0o3_Bicc,		T0o3_BPr,
    T0o3_SetHi,		T0o3_FBPfcc,
    T0o3_FBfcc,		T0o3_unknown_0x7
} T0o3_code_t;


extern "C" {

void		subcc_instr_il          (uint64_t*, uint64_t*, uint64_t*, uint8_t*);
void		subcc_instr_rd0_il      (uint64_t*, uint64_t*, uint8_t*);
void		subcc_instr_simm_rd0_il (uint64_t*, uint64_t*, uint8_t*);
void		subcc_instr_simm_il     (uint64_t*, uint64_t*, uint64_t*, uint8_t*);
void		sll_instr_il            (uint64_t*, uint32_t, uint64_t*);
void		srlx_instr_il_32        (uint64_t*, uint32_t, uint64_t*);
uint64_t		srl_instr_il_32         (uint64_t, uint32_t);
void		srlx_instr_il_64        (uint64_t*, uint32_t, uint64_t*);
uint64_t		srl_instr_il_64         (uint64_t, uint32_t);
void		andcc_instr_il          (uint64_t*, uint64_t*, uint64_t*, uint8_t*);
void		andcc_instr_rd0_il      (uint64_t*, uint64_t*, uint8_t*);
void		andcc_instr_simm_rd0_il (uint64_t*, int64_t*, uint8_t*);
void		andcc_instr_simm_il     (uint64_t*, int64_t*, uint64_t*, uint8_t*);

}

// SAM Speedup 

// Main direct lookup table
bool (InstructionEmulator::*InstructionEmulator::DecodeFuncTab[])( InstructionWord& ) = {
  &InstructionEmulator::exec_decode_direct,
  &InstructionEmulator::EXEC_bicc,
  &InstructionEmulator::EXEC_bpcc,
  &InstructionEmulator::EXEC_bpr,
  &InstructionEmulator::exec_op1,
  &InstructionEmulator::exec_op2,
  &InstructionEmulator::exec_op3,
  &InstructionEmulator::exec_saved_restored,
  &InstructionEmulator::DO_T2o3_add,
  &InstructionEmulator::DO_T2o3_sub,
  &InstructionEmulator::DO_T2o3_and,
  &InstructionEmulator::DO_T2o3_andn,
  &InstructionEmulator::DO_T2o3_or,
  &InstructionEmulator::DO_T2o3_orn,
  &InstructionEmulator::DO_T2o3_xor,
  &InstructionEmulator::DO_T2o3_xorn,
  &InstructionEmulator::DO_T2o3_ldst,
  &InstructionEmulator::DO_T2o3_subcc,
  &InstructionEmulator::DO_T2o3_sll,
  &InstructionEmulator::DO_T2o3_srl,
  &InstructionEmulator::DO_T2o3_orcc,
  &InstructionEmulator::DO_T2o3_andcc,
  &InstructionEmulator::DO_T2o3_jmpl,
  &InstructionEmulator::DO_T2o3_smul,
  &InstructionEmulator::DO_T2o3_umul,
  &InstructionEmulator::DO_T2o3_default,
  &InstructionEmulator::EXEC_sethi,
  &InstructionEmulator::DO_T3o3_lduX,
  &InstructionEmulator::DO_T3o3_stX,
  &InstructionEmulator::DO_T3o3_stXa,
  &InstructionEmulator::DO_T3o3_lduXa,
  &InstructionEmulator::DO_T3o3_ldsX,
  &InstructionEmulator::DO_T3o3_fpX,
  &InstructionEmulator::DO_T3o3_ldstubX,
  &InstructionEmulator::EXEC_ret_false,
  &InstructionEmulator::EXEC_RS_illtrap
};

// Direction function invocation lookup tables
int op0_to_fnidx[8] = {
  DECODE_RS_ILLTRAP,
  DECODE_EXEC_BPCC,
  DECODE_EXEC_BICC,
  DECODE_EXEC_BPR,
  DECODE_EXEC_SETHI,
  DECODE_EXEC_RET_FALSE,
  DECODE_EXEC_RET_FALSE,
  DECODE_RS_ILLTRAP
};

// No op1 translation. Call exec_op1 directly. There's a lookup table inside
// that function. 

int op2_to_fnidx[64] = {
  DECODE_DO_ADD, DECODE_DO_AND, DECODE_DO_OR, DECODE_DO_XOR,
  DECODE_DO_SUB, DECODE_DO_ANDN, DECODE_DO_ORN, DECODE_DO_XORN,
  DECODE_DO_T2O3_DEFAULT, DECODE_DO_T2O3_DEFAULT, DECODE_DO_T2O3_UMUL, DECODE_DO_T2O3_SMUL,
  DECODE_DO_T2O3_DEFAULT, DECODE_DO_T2O3_DEFAULT, DECODE_DO_T2O3_DEFAULT, DECODE_DO_T2O3_DEFAULT,
  /* 1 */
  DECODE_DO_T2O3_DEFAULT, DECODE_DO_T2O3_ANDCC, DECODE_DO_T2O3_ORCC, DECODE_DO_T2O3_DEFAULT,
  DECODE_DO_T2O3_SUBCC, DECODE_DO_T2O3_DEFAULT, DECODE_DO_T2O3_DEFAULT, DECODE_DO_T2O3_DEFAULT,
  DECODE_DO_T2O3_DEFAULT, DECODE_DO_T2O3_DEFAULT, DECODE_DO_T2O3_DEFAULT, DECODE_DO_T2O3_DEFAULT,
  DECODE_DO_T2O3_DEFAULT, DECODE_DO_T2O3_DEFAULT, DECODE_DO_T2O3_DEFAULT, DECODE_DO_T2O3_DEFAULT,
  /* 2 */
  DECODE_DO_T2O3_DEFAULT, DECODE_DO_T2O3_DEFAULT, DECODE_DO_T2O3_DEFAULT, DECODE_DO_T2O3_DEFAULT,
  DECODE_DO_T2O3_DEFAULT, DECODE_DO_T2O3_SLL, DECODE_DO_T2O3_SRL, DECODE_DO_T2O3_DEFAULT,
  DECODE_DO_T2O3_DEFAULT, DECODE_DO_T2O3_DEFAULT, DECODE_DO_T2O3_DEFAULT, DECODE_DO_T2O3_DEFAULT,
  DECODE_DO_T2O3_DEFAULT, DECODE_DO_T2O3_DEFAULT, DECODE_DO_T2O3_DEFAULT, DECODE_DO_T2O3_DEFAULT,
  /* 3 */
  DECODE_DO_T2O3_DEFAULT, DECODE_EXEC_SAVED_RESTORED, DECODE_DO_T2O3_DEFAULT, DECODE_DO_T2O3_DEFAULT,
  DECODE_EXEC_RET_FALSE, DECODE_EXEC_RET_FALSE, DECODE_EXEC_RET_FALSE, DECODE_DO_T2O3_DEFAULT,
  DECODE_DO_T2O3_JMPL, DECODE_DO_T2O3_DEFAULT, DECODE_DO_T2O3_DEFAULT, DECODE_DO_T2O3_DEFAULT,
  DECODE_DO_T2O3_DEFAULT, DECODE_EXEC_OP2, DECODE_EXEC_OP2, DECODE_DO_T2O3_DEFAULT
};

int op3_to_fnidx[64] = {
  DECODE_DO_T3O3_LDUX, DECODE_DO_T3O3_LDUX, DECODE_DO_T3O3_LDUX, DECODE_EXEC_OP3,
  DECODE_DO_T3O3_STX, DECODE_DO_T3O3_STX, DECODE_DO_T3O3_STX, DECODE_EXEC_OP3,
  DECODE_DO_T3O3_LDSX, DECODE_DO_T3O3_LDSX, DECODE_DO_T3O3_LDSX, DECODE_DO_T3O3_LDUX,
  DECODE_EXEC_OP3, DECODE_DO_T3O3_LDSTUBX, DECODE_DO_T3O3_STX, DECODE_EXEC_OP3,
  /* 1 */
  DECODE_DO_T3O3_LDUXA, DECODE_DO_T3O3_LDUXA, DECODE_DO_T3O3_LDUXA, DECODE_EXEC_OP3,
  DECODE_DO_T3O3_STXA, DECODE_DO_T3O3_STXA, DECODE_DO_T3O3_STXA, DECODE_EXEC_OP3,
  DECODE_DO_T3O3_LDUXA, DECODE_DO_T3O3_LDUXA, DECODE_DO_T3O3_LDUXA, DECODE_DO_T3O3_LDUXA,
  DECODE_EXEC_OP3, DECODE_DO_T3O3_LDSTUBX, DECODE_DO_T3O3_STXA, DECODE_EXEC_OP3,
  /* 2 */
  DECODE_DO_T3O3_FPX, DECODE_EXEC_OP3, DECODE_EXEC_OP3, DECODE_DO_T3O3_FPX,
  DECODE_DO_T3O3_FPX, DECODE_EXEC_OP3, DECODE_EXEC_OP3, DECODE_DO_T3O3_FPX,
  DECODE_EXEC_OP3, DECODE_EXEC_OP3, DECODE_EXEC_OP3, DECODE_EXEC_OP3,
  DECODE_EXEC_OP3, DECODE_EXEC_OP3, DECODE_EXEC_OP3, DECODE_EXEC_OP3,
  /* 3 */
  DECODE_DO_T3O3_FPX, DECODE_EXEC_OP3, DECODE_EXEC_OP3, DECODE_DO_T3O3_FPX,
  DECODE_DO_T3O3_FPX, DECODE_EXEC_OP3, DECODE_EXEC_OP3, DECODE_DO_T3O3_FPX,
  DECODE_EXEC_OP3, DECODE_EXEC_OP3, DECODE_EXEC_OP3, DECODE_EXEC_OP3,
  DECODE_EXEC_OP3, DECODE_EXEC_OP3, DECODE_EXEC_OP3, DECODE_EXEC_OP3
};

/////////////////////////////////////////////////////
//
//  This routine is the only routine which
//  decodes incoming instruction and as well
//  executes it.
//  Routine is invoked form cpu_cycle.c 
//  (from main execution entry point ot inner loop)

//  TODO: Instruction tracing might be located inside
//        this routine

bool InstructionEmulator::exec_decode_direct( InstructionWord &iw )
{
  switch (iw.op())
    {
    case 0:
      return (this->*DecodeFuncTab[iw.decode_fn_idx=op0_to_fnidx[iw.op2()]])(iw); 
    case 1:
      iw.decode_fn_idx=DECODE_EXEC_OP1;
      return exec_op1(iw);
    case 2:
      return (this->*DecodeFuncTab[iw.decode_fn_idx=op2_to_fnidx[iw.op3()]])(iw);
    case 3:
      return (this->*DecodeFuncTab[iw.decode_fn_idx=op3_to_fnidx[iw.op3()]])(iw);
    }
}

bool InstructionEmulator::exec_decode_me( InstructionWord &iw )
{
    int         rs1, rd, rs2, simm;
    uint32_t    asi;
    T3o3_code_t op3c;
    uint64_t     op_rs1, op_rs2;

// cerr << "DEBUG: strand/bcore/simkern: " << iw.getPc() << ": " << iw.toString() << endl;;

    switch ((ty_code_t)iw.op()){
    case Ty_0:
	    switch (iw.op2()) {
	    case T0o3_Bicc:	            
		    EXEC_bicc ( iw );
		    return true;
	    case T0o3_BPcc:
		    EXEC_bpcc ( iw );
		    return true;
	    case T0o3_BPr:
		    EXEC_bpr ( iw );
		    return true;
	    case T0o3_SetHi:
		    // checkTrapBeforeCommit(iw);
		    ireg_->set( iw.rd(), iw.imm22() << 10 );
		    return true;
	    case T0o3_FBfcc:
		    return false;

	    case T0o3_FBPfcc:
		    return false;

// 	    case T0o3_Illtrap:
// 	    case T0o3_unknown_0x7:
// 		    RIESLING_TRAP( Sf_Trap::illegal_instruction );
// 		    return true;
	    default:
	      cout << iw.getPc() << ": " << endl;
	      iw.toString;
	      RIESLING_THROW_DOMAIN_ERROR( "Internal error" );
	      break;
	    }
    case Ty_1:
      //iw.decode_fn_idx = DECODE_EXEC_OP1;
	   return exec_op1 ( iw );
	   // return true;

    case Ty_2:
	    rs1  = iw.rs1();
	    rd   = iw.rd();

	    ///////

	    if (iw.i()) {
		simm = iw.simm13();
		op_rs2 = simm;
	    } else {
		op_rs2 = ireg_->get( iw.rs2() );
	    }
	    op_rs1 = ireg_->get( rs1 );


	    switch (iw.op3()) {
	    case T2o3_add :
		// checkTrapBeforeCommit(iw);
		ireg_->set( rd, op_rs1 + op_rs2 );
		return true;
	    case T2o3_and :
		// checkTrapBeforeCommit(iw);
		ireg_->set( rd, op_rs1 & op_rs2 );
		return true;
	    case T2o3_andn :
		// checkTrapBeforeCommit(iw);
		ireg_->set( rd, op_rs1 & ~( op_rs2 ) );
		return true;
	    case T2o3_or :
		// checkTrapBeforeCommit(iw);
		ireg_->set( rd, op_rs1 | op_rs2 );
		return true;
	    case T2o3_orn :
		// checkTrapBeforeCommit(iw);
		ireg_->set( rd, op_rs1 | ~( op_rs2 ) );
		return true;
	    case T2o3_xor :
		// checkTrapBeforeCommit(iw);
		ireg_->set( rd, op_rs1 ^ op_rs2 );
		return true;
	    case T2o3_xnor :
		// checkTrapBeforeCommit(iw);
		ireg_->set( rd, op_rs1 ^ ~( op_rs2 ) );
		return true;
	    case T2o3_sub :
		// checkTrapBeforeCommit(iw);
		ireg_->set( rd, op_rs1 - op_rs2 );
		return true;
	    case T2o3_fpop_0x34 :
		return false;
	    case T2o3_fpop_0x35 :
		return false;
	    case T2o3_gop :
		return false;
	    }       

	    ///////
	    
	    if (iw.i()) {

		    /* register OP immediate -> register forms */
		    switch (iw.op3()) {

			case T2o3_subcc :
			{
        		    // checkTrapBeforeCommit(iw);
			    uint64_t tmp;
			    uint8_t ccr_tmp;
			    subcc_instr_il(&op_rs1, &op_rs2, &tmp, &ccr_tmp);
			    ccr_->setByte( ccr_tmp );
			    ireg_->set( rd, tmp );
			    return true;
			}
			case T2o3_sll :
 		          // checkTrapBeforeCommit(iw);
			  if (rd != 0) {
			    if (iw.x()) {
			      simm = iw.shcnt64();
			    } else {
			      simm = iw.shcnt32();
			    }

			    uint64_t tmp;
			    sll_instr_il(&op_rs1, simm, &tmp);
			    ireg_->set( rd, tmp );
			  }
			  return true;

			case T2o3_srl :
 		          // checkTrapBeforeCommit(iw);
			  if (rd != 0) {
			    if (iw.x()) {
			      uint64_t tmp;
			      simm = iw.shcnt64();
#if HOST64BIT
			      srlx_instr_il_64(&op_rs1, simm & 0x3F, &tmp);
#else
			      srlx_instr_il_32(&op_rs1, simm & 0x3F, &tmp);
#endif
			      ireg_->set( rd, tmp );
			    } else {
			      simm = iw.shcnt32();
#if HOST64BIT
			      ireg_->set( rd, srl_instr_il_64 (op_rs1, simm & 0x1F) );
#else
			      ireg_->set( rd, srl_instr_il_32 (op_rs1, simm & 0x1F) );
#endif
			    }
			  }
			  return true;
			case T2o3_andcc :
			{
 		                // checkTrapBeforeCommit(iw);
				int64_t stmp = simm;
				uint8_t ccr_tmp;
				uint64_t tmp_result;
				if (rd == 0) {
				    andcc_instr_simm_rd0_il (&op_rs1, &stmp, &ccr_tmp);
				} else {
				    andcc_instr_simm_il (&op_rs1, &stmp, &tmp_result, &ccr_tmp);
				}
				ccr_->setByte( ccr_tmp );
				ireg_->set( rd, tmp_result );
				return true;
			}

			case T2o3_jmpl :
			    exec_op2( iw );
			  return true;

			case T2o3_saved :/* FIXME - are these valid */
			  exec_saved_restored(iw);
			  return true;

			case T2o3_smul :
			{
			    // checkTrapBeforeCommit(iw);
			    uint64_t tmp_result;
			    uint32_t tmp_y;
			    smul_asm ( LO_W (op_rs1), simm , &tmp_result, &tmp_y); 
			    ireg_->set( rd, tmp_result );
			    y_->setY( tmp_y );
			    return true;
			}

			case T2o3_umul :
			{
			    // checkTrapBeforeCommit(iw);
			    uint64_t tmp_result;
			    uint32_t tmp_y;
			    umul_asm ( LO_W (op_rs1), simm , &tmp_result, &tmp_y );
			    ireg_->set( rd, tmp_result );
			    y_->setY( tmp_y );
			    return true;
			} 

			case T2o3_orcc :
			  {
			      // checkTrapBeforeCommit(iw);
			      uint64_t tmp_result;
			      uint8_t tmp_ccr;
			      int64_t stmp = (int64_t) simm;
			      orcc_instr(&op_rs1, (uint64_t*)&stmp, &tmp_result, &tmp_ccr);
			      ireg_->set( rd, tmp_result );
			      ccr_->setByte( tmp_ccr );
			      return true;
			  }
			default:
			      instrAccepted_ = true;
			      exec_op2( iw );
			      return instrAccepted_;
			}

	    } else {
		// iw.i == 0

		    rs2 = iw.rs2();
		    uint64_t tmp_result;
		    uint32_t tmp_y;
		    uint8_t tmp_ccr;

		    /* register OP register -> register forms */
		    switch ( iw.op3() ){

		    case T2o3_subcc :
			// checkTrapBeforeCommit(iw);
			subcc_instr_il (&op_rs1, &op_rs2, &tmp_result, &tmp_ccr);
			ireg_->set( rd, tmp_result );
			ccr_->setByte( tmp_ccr );
			return true;

		    case T2o3_andcc :
			// checkTrapBeforeCommit(iw);
			andcc_instr_il (&op_rs1, &op_rs2, &tmp_result, &tmp_ccr);
			ireg_->set( rd, tmp_result );
			ccr_->setByte( tmp_ccr );
			return true;

		    case T2o3_sll :
			// checkTrapBeforeCommit(iw);
			if (iw.x()) {
			    op_rs2 &= 0x3f;
			} else {
			    op_rs2 &= 0x1f;
			}
			sll_instr_il(&op_rs1, op_rs2, &tmp_result);
			ireg_->set( rd, tmp_result );
			return true;

		    case T2o3_srl :

			// checkTrapBeforeCommit(iw);
			if (rd != 0) {
			    if (iw.x()) {
#if HOST64BIT
				srlx_instr_il_64(&op_rs1, op_rs2 & 0x3F, &tmp_result );
#else
				srlx_instr_il_32(&op_rs1, op_rs2 & 0x3F, &tmp_result );
#endif
				ireg_->set( rd, tmp_result );
			    } 
			    else {
#if HOST64BIT
				ireg_->set( rd,  srl_instr_il_64 (op_rs1, op_rs2 & 0x1F) );
#else
				ireg_->set( rd,  srl_instr_il_32 (op_rs1, op_rs2 & 0x1F) );
#endif
			    }
			}
			return true;

		    case T2o3_jmpl :
		      if (rd != 0) {
			exec_JMPL_rd15 ( iw );
		      } else {
			exec_op2( iw );
		      }
		      return true;

		    case T2o3_saved :
		      exec_saved_restored(iw);
		      return true;

		    case T2o3_retry :
		      exec_op2( iw );
		      return true;

		    case T2o3_restore :
		      exec_op2( iw );
		      return true;

		    case T2o3_smul :
			// checkTrapBeforeCommit(iw);
		      smul_asm ( LO_W (op_rs1), LO_W (op_rs2), &tmp_result, &tmp_y);
		      ireg_->set( rd, tmp_result );
		      y_->setY( tmp_y );
		      return true;

		    case T2o3_umul :
			// checkTrapBeforeCommit(iw);
		      umul_asm ( LO_W (op_rs1), LO_W (op_rs2), &tmp_result, &tmp_y);
		      ireg_->set( rd, tmp_result );
		      y_->setY( tmp_y );
		      return true;

		    case T2o3_orcc :
			// checkTrapBeforeCommit(iw);
		      orcc_instr (&op_rs1, &op_rs2, &tmp_result, &tmp_ccr );
		      ireg_->set( rd, tmp_result );
		      ccr_->setByte( tmp_ccr );
		      return true;

		    default:
			instrAccepted_ = true;
			exec_op2( iw );
			return instrAccepted_;
		    }
	    }

    case Ty_3:
      {
	    uint64_t ea = 0;

	    rs1  = iw.rs1();
	    rd   = iw.rd();
	    op3c = (T3o3_code_t)iw.op3();

	    if (iw.i()) {
		simm = iw.simm13();
		ea   = simm + ireg_->get(rs1);
	    }
	    else {
		rs2 = iw.rs2();
		ea  = ireg_->get(rs1) + ireg_->get(rs2);
	    }

	    switch ( op3c ) {
	    case T3o3_lduw:
	      exec_LDUW( iw, ea );
	      return true;
	    case T3o3_ldub:
	      exec_LDUB( iw, ea );
	      return true;

	    case T3o3_lduh:
	      exec_LDUH( iw, ea );
	      return true;

	    case T3o3_ldd:
	      exec_op3( iw );
	      return true;

	    case T3o3_ldx:
	      exec_LDX( iw, ea );
	      return true;

	    case T3o3_ldf:  
	    case T3o3_lddf:  
		  exec_LDF( iw, ea );
		  return true;

	    case T3o3_stf:  
	    case T3o3_stdf:  
		  exec_STF( iw, ea );
		  return true;

	    case T3o3_ldfa:  
	    case T3o3_lddfa:  
		  exec_LDF_ASI( iw, ea );
		  return true;

	    case T3o3_stfa:  
	    case T3o3_stdfa:  
		  exec_STF_ASI( iw, ea );
		  return true;

	    case T3o3_stw:
	    case T3o3_stb:
	    case T3o3_sth:
	    case T3o3_stx:
		  exec_STORE( iw, ea );
		  return true;

	    case T3o3_std:
	      exec_op3( iw );
	      return true;

	    case T3o3_ldsw:
	    case T3o3_ldsb:
	    case T3o3_ldsh:
	      exec_LOAD_SIGNED ( iw, ea );
	      return true;

	    case T3o3_lduwa:
	    case T3o3_lduba:
	    case T3o3_lduha:
	    case T3o3_ldswa:
	    case T3o3_ldxa:
	    case T3o3_ldsba:
	    case T3o3_ldsha:
	      exec_LOAD_ASI  ( iw, ea );
	      return true;
	    case T3o3_stwa:
	    case T3o3_stba:
	    case T3o3_stha:
	    case T3o3_stxa:
	      exec_STORE_ASI( iw, ea );
	      return true;  
	    case T3o3_ldstub1:
	    case T3o3_ldstuba:
	      exec_LDSTUB ( iw, ea );
	      return true;
	    case T3o3_casxa:
	      if ( iw.i() == 0) {
		  asi =  iw.immAsi();
// TODO FIXME
#if 0
		  if ((asi == e_ASI_PRIMARY) && (rd != 0)) {
		      exec_CASXA_80 (sp, sp->current_reg[rs1], instr);
		      return true;
		  }
#endif
	      }
	      exec_op3( iw );
	      return true;
	    default:
	      exec_op3( iw );
	      return true;
	    }
      }

    }
    RIESLING_THROW_DOMAIN_ERROR( "Internal error" );
}

// SAM Speedup
// Direct call functions
// These are broken down from exec_decode_me
// Replace with Hendrik's uber functions when available

bool InstructionEmulator::DO_T2o3_add( InstructionWord &iw ) {
  uint64_t     op_rs1, op_rs2;
  if (iw.i()) {
    op_rs2 = iw.simm13();
  } else {
    op_rs2 = ireg_->get( iw.rs2() );
  }
  op_rs1 = ireg_->get( iw.rs1() );

  //checkTrapBeforeCommit(iw);
  ireg_->set( iw.rd(), op_rs1 + op_rs2 );
  //iw.decode_fn_idx = DECODE_DO_ADD;
  return true;
}

bool InstructionEmulator::DO_T2o3_and( InstructionWord &iw ) {
  uint64_t     op_rs1, op_rs2;
  if (iw.i()) {
    op_rs2 = iw.simm13();
  } else {
    op_rs2 = ireg_->get( iw.rs2() );
  }
  op_rs1 = ireg_->get( iw.rs1() );

  //checkTrapBeforeCommit(iw);
  ireg_->set( iw.rd(), op_rs1 & op_rs2 );
  //iw.decode_fn_idx = DECODE_DO_AND;
  return true;
}

bool InstructionEmulator::DO_T2o3_andn( InstructionWord &iw ) {
  uint64_t     op_rs1, op_rs2;
  if (iw.i()) {
    op_rs2 = iw.simm13();
  } else {
    op_rs2 = ireg_->get( iw.rs2() );
  }
  op_rs1 = ireg_->get( iw.rs1() );

  //checkTrapBeforeCommit(iw);
  ireg_->set( iw.rd(), op_rs1 & ~( op_rs2 ) );
  //iw.decode_fn_idx = DECODE_DO_ANDN;
  return true;
}

bool InstructionEmulator::DO_T2o3_or( InstructionWord &iw ) {
  uint64_t     op_rs1, op_rs2;
  if (iw.i()) {
    op_rs2 = iw.simm13();
  } else {
    op_rs2 = ireg_->get( iw.rs2() );
  }
  op_rs1 = ireg_->get( iw.rs1() );

  //checkTrapBeforeCommit(iw);
  ireg_->set( iw.rd(), op_rs1 | op_rs2 );
  //iw.decode_fn_idx = DECODE_DO_OR;
  return true;
}

bool InstructionEmulator::DO_T2o3_orn( InstructionWord &iw ) {
  uint64_t     op_rs1, op_rs2;
  if (iw.i()) {
    op_rs2 = iw.simm13();
  } else {
    op_rs2 = ireg_->get( iw.rs2() );
  }
  op_rs1 = ireg_->get( iw.rs1() );

  //checkTrapBeforeCommit(iw);
  ireg_->set( iw.rd(), op_rs1 | ~( op_rs2 ) );
  //iw.decode_fn_idx = DECODE_DO_ORN;
  return true;
}

bool InstructionEmulator::DO_T2o3_xor( InstructionWord &iw ) {
  uint64_t     op_rs1, op_rs2;
  if (iw.i()) {
    op_rs2 = iw.simm13();
  } else {
    op_rs2 = ireg_->get( iw.rs2() );
  }
  op_rs1 = ireg_->get( iw.rs1() );

  //checkTrapBeforeCommit(iw);
  ireg_->set( iw.rd(), op_rs1 ^ op_rs2 );
  //iw.decode_fn_idx = DECODE_DO_XOR;
  return true;
}

bool InstructionEmulator::DO_T2o3_xorn( InstructionWord &iw ) {
  uint64_t     op_rs1, op_rs2;
  if (iw.i()) {
    op_rs2 = iw.simm13();
  } else {
    op_rs2 = ireg_->get( iw.rs2() );
  }
  op_rs1 = ireg_->get( iw.rs1() );

  //checkTrapBeforeCommit(iw);
  ireg_->set( iw.rd(), op_rs1 ^ ~( op_rs2 ) );
  //iw.decode_fn_idx = DECODE_DO_XORN;
  return true;
}

bool InstructionEmulator::DO_T2o3_sub( InstructionWord &iw ) {
  uint64_t     op_rs1, op_rs2;
  if (iw.i()) {
    op_rs2 = iw.simm13();
  } else {
    op_rs2 = ireg_->get( iw.rs2() );
  }
  op_rs1 = ireg_->get( iw.rs1() );

  //checkTrapBeforeCommit(iw);
  ireg_->set( iw.rd(), op_rs1 - op_rs2 );
  //iw.decode_fn_idx = DECODE_DO_SUB;
  return true;
}

bool InstructionEmulator::DO_T2o3_ldst( InstructionWord &iw ) {
  int         rs1, rd, rs2, simm;
  uint32_t    asi;
  T3o3_code_t op3c;
  uint64_t     op_rs1, op_rs2;
  
  uint64_t ea = 0;
  rs1  = iw.rs1();
  rd   = iw.rd();
  op3c = (T3o3_code_t)iw.op3();

  if (iw.i()) {
    simm = iw.simm13();
    ea   = simm + ireg_->get(rs1);
  }
  else {
    rs2 = iw.rs2();
    ea  = ireg_->get(rs1) + ireg_->get(rs2);
  }

  switch ( op3c ) {
  case T3o3_lduw:
    exec_LDUW( iw, ea );
    return true;
  case T3o3_ldub:
    exec_LDUB( iw, ea );
    return true;

  case T3o3_lduh:
    exec_LDUH( iw, ea );
    return true;

  case T3o3_ldd:
    exec_op3( iw );
    return true;

  case T3o3_ldx:
    exec_LDX( iw, ea );
    return true;

  case T3o3_ldf:  
  case T3o3_lddf:  
    exec_LDF( iw, ea );
    return true;

  case T3o3_stf:  
  case T3o3_stdf:  
    exec_STF( iw, ea );
    return true;

  case T3o3_ldfa:  
  case T3o3_lddfa:  
    exec_LDF_ASI( iw, ea );
    return true;

  case T3o3_stfa:  
  case T3o3_stdfa:  
    exec_STF_ASI( iw, ea );
    return true;

  case T3o3_stw:
  case T3o3_stb:
  case T3o3_sth:
  case T3o3_stx:
    exec_STORE( iw, ea );
    return true;

  case T3o3_std:
    RIESLING_THROW_DOMAIN_ERROR( "Internal error" );
    return false;

  case T3o3_ldsw:
  case T3o3_ldsb:
  case T3o3_ldsh:
    exec_LOAD_SIGNED ( iw, ea );
    return true;

  case T3o3_lduwa:
  case T3o3_lduba:
  case T3o3_lduha:
  case T3o3_ldswa:
  case T3o3_ldxa:
  case T3o3_ldsba:
  case T3o3_ldsha:
    exec_LOAD_ASI  ( iw, ea );
    return true;
  case T3o3_stwa:
  case T3o3_stba:
  case T3o3_stha:
  case T3o3_stxa:
    exec_STORE_ASI( iw, ea );
    return true;  
  case T3o3_ldstub1:
  case T3o3_ldstuba:
    exec_LDSTUB ( iw, ea );
    return true;
  case T3o3_casxa:
#if 0
    if ( iw.i() == 0) {
      asi =  iw.immAsi();
      // TODO FIXME
      if ((asi == e_ASI_PRIMARY) && (rd != 0)) {
	exec_CASXA_80 (sp, sp->current_reg[rs1], instr);
	return true;
      }
    }
#endif
    RIESLING_THROW_DOMAIN_ERROR( "Internal error" );
    return false;
  default:
    RIESLING_THROW_DOMAIN_ERROR( "Internal error" );
    return false;
  }
}

bool InstructionEmulator::DO_T2o3_smul( InstructionWord &iw ) {
  uint64_t tmp_result;
  uint32_t tmp_y;
  uint64_t     op_rs1, op_rs2;
  
  if (iw.i()) {
    op_rs2 = iw.simm13();
  } else {
    op_rs2 = ireg_->get( iw.rs2() );
  }
  op_rs1 = ireg_->get( iw.rs1() );
  
  //checkTrapBeforeCommit(iw);
  smul_asm ( LO_W (op_rs1), LO_W (op_rs2), &tmp_result, &tmp_y);
  ireg_->set( iw.rd(), tmp_result );
  y_->setY( tmp_y );
  //iw.decode_fn_idx = DECODE_DO_T2O3_SMUL;
  return true;
}

bool InstructionEmulator::DO_T2o3_umul( InstructionWord &iw ) {
  uint64_t tmp_result;
  uint32_t tmp_y;
  uint64_t     op_rs1, op_rs2;

  if (iw.i()) {
    op_rs2 = iw.simm13();
  } else {
    op_rs2 = ireg_->get( iw.rs2() );
  }
  op_rs1 = ireg_->get( iw.rs1() );
  
  //checkTrapBeforeCommit(iw);
  umul_asm ( LO_W (op_rs1), iw.i() ? op_rs2 : LO_W (op_rs2) , &tmp_result, &tmp_y );
  ireg_->set( iw.rd(), tmp_result );
  y_->setY( tmp_y );
  //iw.decode_fn_idx = DECODE_DO_T2O3_UMUL;
  return true;
}

bool InstructionEmulator::DO_T2o3_andcc ( InstructionWord &iw ) {
 		                //checkTrapBeforeCommit(iw);
  uint8_t ccr_tmp;
  uint64_t tmp_result;
  uint64_t     op_rs1, op_rs2;

  op_rs1 = ireg_->get( iw.rs1() );

  //iw.decode_fn_idx = DECODE_DO_T2O3_ANDCC;
  if (iw.i()) {
    op_rs2 = iw.simm13();
    if (iw.rd() == 0) {
      andcc_instr_simm_rd0_il (&op_rs1, (int64_t *)&op_rs2, &ccr_tmp);
    } else {
      andcc_instr_simm_il (&op_rs1, (int64_t *)&op_rs2, &tmp_result, &ccr_tmp);
    }
    ccr_->setByte( ccr_tmp );
    ireg_->set( iw.rd(), tmp_result );
    return true;
  } else {
    op_rs2 = ireg_->get( iw.rs2() );
    //checkTrapBeforeCommit(iw);
    andcc_instr_il (&op_rs1, &op_rs2, &tmp_result, &ccr_tmp);
    ireg_->set( iw.rd(), tmp_result );
    ccr_->setByte( ccr_tmp );
    return true;
  }
  
}

bool InstructionEmulator::DO_T2o3_orcc ( InstructionWord &iw ) {
 		                //checkTrapBeforeCommit(iw);
  uint8_t ccr_tmp;
  uint64_t tmp_result;
  uint64_t     op_rs1, op_rs2;

  op_rs1 = ireg_->get( iw.rs1() );
  //checkTrapBeforeCommit(iw);
  //iw.decode_fn_idx = DECODE_DO_T2O3_ORCC;
  if (iw.i()) {
    op_rs2 = iw.simm13();
    
    orcc_instr(&op_rs1, (uint64_t*)&op_rs2, &tmp_result, &ccr_tmp);
    ireg_->set( iw.rd(), tmp_result );
    ccr_->setByte( ccr_tmp );
    return true;
  } else {
    op_rs2 = ireg_->get( iw.rs2() );
    
    orcc_instr (&op_rs1, &op_rs2, &tmp_result, &ccr_tmp );
    ireg_->set( iw.rd(), tmp_result );
    ccr_->setByte( ccr_tmp );
    return true;
  }
  
}
bool InstructionEmulator::DO_T2o3_subcc ( InstructionWord &iw ) {
 		                //checkTrapBeforeCommit(iw);
  uint8_t ccr_tmp;
  uint64_t tmp_result;
  uint64_t     op_rs1, op_rs2;

  op_rs1 = ireg_->get( iw.rs1() );

  //iw.decode_fn_idx = DECODE_DO_T2O3_SUBCC;  
  if ( iw.i() ) {
    op_rs2 = iw.simm13();
    //checkTrapBeforeCommit(iw);
    subcc_instr_il(&op_rs1, &op_rs2, &tmp_result, &ccr_tmp);
    ccr_->setByte( ccr_tmp );
    ireg_->set( iw.rd(), tmp_result );
    return true;
  } else { 
    //checkTrapBeforeCommit(iw);
    op_rs2 = ireg_->get( iw.rs2() );
    subcc_instr_il (&op_rs1, &op_rs2, &tmp_result, &ccr_tmp);
    ireg_->set( iw.rd(), tmp_result );
    ccr_->setByte( ccr_tmp );
    return true;
  }
}

bool InstructionEmulator::DO_T2o3_sll ( InstructionWord &iw ) {
 		                //checkTrapBeforeCommit(iw);
  uint8_t ccr_tmp;
  uint64_t tmp_result;
  uint64_t     op_rs1, op_rs2;
  int simm;
  uint32_t rd = iw.rd();

  op_rs1 = ireg_->get( iw.rs1() );

  //iw.decode_fn_idx = DECODE_DO_T2O3_SLL;
  //checkTrapBeforeCommit(iw);  
  if ( iw.i() ) {
    op_rs2 = iw.simm13();
    if (rd != 0) {
      if (iw.x()) {
	simm = iw.shcnt64();
      } else {
	simm = iw.shcnt32();
      }
      sll_instr_il(&op_rs1, simm, &tmp_result);
      ireg_->set( rd, tmp_result );
    }
    return true;
  } else {
    op_rs2 = ireg_->get( iw.rs2() );
    if (iw.x()) {
      op_rs2 &= 0x3f;
    } else {
      op_rs2 &= 0x1f;
    }
    sll_instr_il(&op_rs1, op_rs2, &tmp_result);
    ireg_->set( rd, tmp_result );
    return true;
  }
}

bool InstructionEmulator::DO_T2o3_srl ( InstructionWord &iw ) {
 		                //checkTrapBeforeCommit(iw);
  uint8_t ccr_tmp;
  uint64_t tmp_result;
  uint64_t     op_rs1, op_rs2;
  uint32_t rd = iw.rd();
  int simm;

  op_rs1 = ireg_->get( iw.rs1() );
  //checkTrapBeforeCommit(iw);  
  //iw.decode_fn_idx = DECODE_DO_T2O3_SRL;

  if ( iw.i() ) {
    op_rs2 = iw.simm13();
    if (rd != 0) {
      if (iw.x()) {
	simm = iw.shcnt64();
#if HOST64BIT
	srlx_instr_il_64(&op_rs1, simm & 0x3F, &tmp_result);
#else
	srlx_instr_il_32(&op_rs1, simm & 0x3F, &tmp_result);
#endif
	ireg_->set( rd, tmp_result );
      } else {
	simm = iw.shcnt32();
#if HOST64BIT
	ireg_->set( rd, srl_instr_il_64 (op_rs1, simm & 0x1F) );
#else
	ireg_->set( rd, srl_instr_il_32 (op_rs1, simm & 0x1F) );
#endif
      }
    }
    return true;
  } else {
    op_rs2 = ireg_->get( iw.rs2() );
    if (rd != 0) {
      if (iw.x()) {
#if HOST64BIT
	srlx_instr_il_64(&op_rs1, op_rs2 & 0x3F, &tmp_result );
#else
	srlx_instr_il_32(&op_rs1, op_rs2 & 0x3F, &tmp_result );
#endif
	ireg_->set( rd, tmp_result );
      } 
      else {
#if HOST64BIT
	ireg_->set( rd,  srl_instr_il_64 (op_rs1, op_rs2 & 0x1F) );
#else
	ireg_->set( rd,  srl_instr_il_32 (op_rs1, op_rs2 & 0x1F) );
#endif
      }
    }
    return true;

  }
}

bool InstructionEmulator::DO_T2o3_jmpl ( InstructionWord &iw ) {
 		                //checkTrapBeforeCommit(iw);
  uint8_t ccr_tmp;
  uint64_t tmp_result;
  uint64_t     op_rs1, op_rs2;

  op_rs1 = ireg_->get( iw.rs1() );
  //checkTrapBeforeCommit(iw);  
  //iw.decode_fn_idx = DECODE_DO_T2O3_JMPL;
  if ( iw.i() ) {
     instrAccepted_ = true;
     return exec_op2(iw);   
  } else {
    if (iw.rd() != 0) {
      return exec_JMPL_rd15 ( iw );
    } else {
      instrAccepted_ = true;
      return exec_op2( iw );
    }
  }
}

bool InstructionEmulator::DO_T2o3_default ( InstructionWord &iw ) {
  instrAccepted_ = true;
  //iw.decode_fn_idx = DECODE_DO_T2O3_DEFAULT;
  return exec_op2( iw );
}

// SAM Speedup
bool InstructionEmulator::DO_T3o3_lduX(InstructionWord &iw) {
  uint32_t rd = iw.rd();
  uint64_t memValue;
  PaddrT addr;
  
  // checkTrapBeforeCommit(iw);
  // cosim mode : update msync
  if ( rd != 0  || CallbackInterface::cosim) {

    if (iw.i()) {
      addr   = iw.simm13() + ireg_->get(iw.rs1());
    }
    else {
      addr  = ireg_->get(iw.rs1()) + ireg_->get(iw.rs2());
    }
    
    switch(iw.op3()) {
    case T3o3_lduw:
      memValue = readUnsigned( addr, 4, iw );
      if(rd != 0){
          ireg_->set( rd, NumericUtils::getLoWord( memValue ) );
      }
      break;
    case T3o3_ldub:
      memValue = readUnsigned( addr, 1, iw );
      if(rd != 0){
          ireg_->set( rd, memValue );
      }
      break;
    case T3o3_lduh:
      memValue = readUnsigned( addr, 2, iw );
      if(rd != 0){
          ireg_->set( rd, memValue );
      }
      break;
    case T3o3_ldx:
      memValue = readUnsigned( addr, 8, iw );
      if(rd != 0){
          ireg_->set( rd, memValue );
      }
      break;
    default:
      RIESLING_THROW_DOMAIN_ERROR( "Internal error" );
      return false;
    }
  }
  return true;
}

  // copycat of exec_STORE
bool InstructionEmulator::DO_T3o3_stX(InstructionWord &iw) {
  uint32_t rd = iw.rd();
  uint64_t memValue;
  PaddrT addr;
  uint32_t op3 = iw.op3();
  
  if (iw.i()) {
    addr   = iw.simm13() + ireg_->get(iw.rs1());
  }
  else {
    addr  = ireg_->get(iw.rs1()) + ireg_->get(iw.rs2());
  }
  
  // checkTrapBeforeCommit(iw);
  
  if        (op3 == T3o3_stw) {
    write( addr, 4,  iw, ireg_->get( rd ) );
  } else if (op3 == T3o3_stx) {
    write( addr, 8,  iw, ireg_->get( rd ) );
  } else if (op3 == T3o3_stb) {
    write( addr, 1,  iw, ireg_->get( rd ) );
  } else if (op3 == T3o3_sth) {
    write( addr, 2,  iw, ireg_->get( rd ) );
  } else {
    // we should NEVER get here.
    RIESLING_THROW_DOMAIN_ERROR( "Internal error." );
    return false;
  }
  return true;
}
  
// SAM Speedup
bool InstructionEmulator::DO_T3o3_lduXa(InstructionWord &iw) {
  uint32_t rd = iw.rd();
  uint64_t regValue;
  PaddrT addr;
  uint8_t asi;

  if (iw.i()) {
    asi = asi_->getNative();
    addr   = iw.simm13() + ireg_->get(iw.rs1());
  }
  else {
    asi = iw.immAsi();
    addr  = ireg_->get(iw.rs1()) + ireg_->get(iw.rs2());
  }

  
  if( isXlateAsi( asi ) ){
    // xact.rebuild(addr, asi, getStrand(), MemoryTransaction::READ, 8, iw);
    MemoryTransaction xact( addr, asi, iw, MemoryTransaction::READ, getStrand() );
    
    switch (iw.op3()) {
    case T3o3_lduba:
      regValue = readUnsigned( xact, 1 );
      break;
    case T3o3_ldsba:
      regValue = readSigned( xact, 1 );
      break;
    case T3o3_lduha:
      regValue = readUnsigned( xact, 2 );
      break;
    case T3o3_ldsha:
      regValue = readSigned( xact, 2 );
      break;
    case T3o3_lduwa:
      regValue = readUnsigned( xact, 4 );
      break;
    case T3o3_ldswa:
      regValue = readSigned( xact, 4 );
      break;
    case T3o3_ldxa:
      regValue = readUnsigned( xact, 8 );
      break;
    }
    
    // checkTrapBeforeCommit(i);
    
    if (rd != 0) {
      ireg_->set( rd, regValue );
    }
    
  } else {
    regValue = asiDispRead( asi, addr, iw );
    // checkTrapBeforeCommit(i);
    if ( rd != 0 ) {
      ireg_->set( rd, regValue );
    }
  }
  return true;
}
  
bool InstructionEmulator::DO_T3o3_stXa(InstructionWord &iw) {
  uint32_t rd = iw.rd();
  uint64_t memValue;
  PaddrT addr;
  uint8_t asi;

  if (iw.i()) {
    asi = asi_->getNative();
    addr   = iw.simm13() + ireg_->get(iw.rs1());
  }
  else {
    asi = iw.immAsi();
    addr  = ireg_->get(iw.rs1()) + ireg_->get(iw.rs2());
  }
    
  if ( isXlateAsi( asi ) ) {
    //xact.rebuild(addr, asi, getStrand(), MemoryTransaction::WRITE, 8, iw);
    MemoryTransaction xact( addr, asi, iw, MemoryTransaction::WRITE, getStrand() );
    xact.setData( ireg_->get( rd ) );
    
    // checkTrapBeforeCommit(i);
    
    switch (iw.op3()) {
    case T3o3_stba:
      xact.size(1);
      write( xact, 1 );
      return true;
    case T3o3_stha:
      xact.size(2);
      write( xact, 2 );
      return true;
    case T3o3_stwa:
      xact.size(4);
      write( xact, 4 );
      return true;
    case T3o3_stxa:
      xact.size(8);
      write( xact, 8 );
      return true;
    }
  } else {
    // checkTrapBeforeCommit(i);
    asiDispWrite( asi, addr, ireg_->get( rd ), iw );
    return true;
  }
}

bool InstructionEmulator::DO_T3o3_ldsX(InstructionWord &iw) {
  uint32_t rd = iw.rd();
  PaddrT addr;
  uint_t size;
  uint_t op3;
  uint64_t regValue;

  // cosim mode : update msync
  if ( rd != 0 || CallbackInterface::cosim) {
    if (iw.i()) {
      addr   = iw.simm13() + ireg_->get(iw.rs1());
    }
    else {
      addr  = ireg_->get(iw.rs1()) + ireg_->get(iw.rs2());
    }
    
    op3 = iw.op3();
    if        (op3 == T3o3_ldsw){
      size = 4;
    } else if (op3 == T3o3_ldsb){
      size = 1;
    } else if (op3 == T3o3_ldsh){
      size = 2;
    } else {
      // should NEVER reach here
      RIESLING_THROW_DOMAIN_ERROR( "Internal error." );
      return false;
    }
    
    regValue = readSigned( addr, size, iw );
    // checkTrapBeforeCommit(iw);
    if(rd != 0){
        ireg_->set( rd, regValue );
    }
  }  
  return true;
}

bool InstructionEmulator::DO_T3o3_fpX(InstructionWord &iw) {
  uint32_t rd = iw.rd();
  uint64_t memValue;
  PaddrT addr;
  uint32_t op3 = iw.op3();
  
  if (iw.i()) {
    addr   = iw.simm13() + ireg_->get(iw.rs1());
  }
  else {
    addr  = ireg_->get(iw.rs1()) + ireg_->get(iw.rs2());
  }
  
  switch(op3) {
  case T3o3_ldf:
  case T3o3_lddf:
    exec_LDF(iw, addr);
    return true;
  case T3o3_stf:
  case T3o3_stdf:
    exec_STF(iw, addr);
    return true;
  case T3o3_ldfa:
  case T3o3_lddfa:
    exec_LDF_ASI(iw, addr);
    return true;
  case T3o3_stfa:
  case T3o3_stdfa:
    exec_STF_ASI(iw, addr);
    return true;    
  }
}

bool InstructionEmulator::DO_T3o3_ldstubX(InstructionWord &iw) {
  uint32_t rd = iw.rd();
  uint64_t memValue;
  PaddrT addr;
  uint32_t op3 = iw.op3();
  
  if (iw.i()) {
    addr   = iw.simm13() + ireg_->get(iw.rs1());
  }
  else {
    addr  = ireg_->get(iw.rs1()) + ireg_->get(iw.rs2());
  }
  exec_LDSTUB(iw, addr);
  return true;
}
